#include "Noyau/Ecran.hpp"
#include "Noyau/Rayon.hpp"
#include "Noyau/Camera.hpp"
#include "Noyau/Environnement.hpp"
#include "Noyau/Lib.hpp"

#include "Algebre/Coord.hpp"
#include "Algebre/Vecteur.hpp"

#include "Formes/LibForm.hpp"

#include "Image/ImageFilePPM.hpp"
#include "Image/ImageFilePng.hpp"
#include "Image/ImageFileJpeg.hpp"
#include "Image/ImageFileTiff.hpp"
#include "Image/ReadImageFile.hpp"

#include "Lumieres/Source.hpp"

#include "Materiaux/Materiau.hpp"
#include "Materiaux/Carreaux.hpp"


#include "Utils/borne.hpp"
#include "Utils/StatusCode.hpp"
#include "Utils/debugstreams.hpp"

#include "Xml/Parser.hpp"
#include "Xml/InterpreteXML.hpp"

#include <iostream>
#include <iomanip>
#include <stdio.h>

#include <boost/assign/list_of.hpp>

using namespace std;
using namespace boost::assign;

bool format_xml(string output) // regarde si le fichier possede l extension xml
{
  if (output.size()<5) // si le nom est plus petit que 4 lettres
    return false;    // on renvoi false
  int j=output.find(".xml");
  if (j!=-1)
    return true;
  else
    return false;
}

int cherche_format(string output) // permet de lire l'extension
{
  if (output.size()<5)
    return -1;
  int format;
  int p=output.find(".jpg");
  if (p!=-1)
    format=0;
  else
    {
      p=output.find(".jpeg");
      if (p!=-1)
	format=0;
      else
	{
	  p=output.find(".png");
	  if (p!=-1)
	    format=1;
	  else
	    {
	      p=output.find(".tif");
	      if (p!=-1)
		format=2;
	      else
		{
		  p=output.find(".tiff");
		  if (p!=-1)
		    format=2;
		  else
		    {
		      p=output.find(".ppm");
		      if (p!=-1)
			format=3;
		      else
			{
			  format=-1;
			}
		    }
		}
	    }
	}
    }
  return format;
}

int main (int argc, char * const argv[]) {
  // traitement des parametres passe a l executable
  if (argc>1)
    {
      vector< string > tab = list_of("-v")("-h")("--debug")("--info");
      vector< string >::const_iterator Begin( tab.begin() ), End( tab.end() );
      if ( find( Begin, End, argv[1] ) == End )
	{
	  cout << "Les parametres possibles sont: -v ou -h, --debug ou --info" << endl;
	  return 0;
	}
      else
	{
	  if (argv[1]==tab[0])
	    {
	      cout << "RJRay version beta 1.0" << endl;
	      return 0;
	    }
	  else if (argv[1]==tab[1])
	    {
	      cout << "Consulter le readme.txt" << endl;
	      return 0;
	    }
	  else if (argv[1]==tab[2])
	    {
	      Parser::setLevel( DEBUG, 0 );
	      Parser::setLevel( DEBUG, 1 );
	    }
	  else if (argv[1]==tab[3])
	    {
	      Parser::setLevel( INFO, 0 );
	      Parser::setLevel( INFO, 1 );
	    }
	}
    }
  // affichage du titre
  cout << setfill('#') << setw(54) << '#' << endl;
  cout << '#' << setfill(' ') << setw(53) << '#' << endl;
  cout << '#' << setw(28) << "RJRay" << setw(25) << '#' << endl;
  cout << '#' << setw(30) << "Beta 1.0" << setw(23) << '#' << endl;
  cout << '#' << setfill(' ') << setw(53) << '#' << endl;
  cout << setfill('#') << setw(54) << '#' << endl;
  cout << endl << endl;
  
  int format=0; // numerote le format choisi par l'utilisateur par défaut vaut zero
  int qualite=97; // taux de qualite pour le jpeg, par defaut 97
  char ouinon='o'; // permet de savoir si on doit recommencer la boucle ou non
  string poubelle; // on vide dans cette chaine les cin qui ont échoué.
  
  do
    {
      cout << "Entrer le nom du fichier xml : " << flush;
      string input;
      cin >> ws >> input;
      if (cin.fail())
	{
	  cout << "Nom de fichier invalide" << endl;
	  cin.clear();
	  getline(cin, poubelle);
	}
      else
	{
	  
	  if (format_xml(input))
	    {
	      cout << "Entrer le nom du fichier de sortie,\navec extension (.jpg, .png, .tif, .ppm) : " << flush;
	      string output;
	      cin >> ws >> output;
	      if (!cin.fail())
		{
		  format=cherche_format(output);
		  if (format==0) // cas du Jpeg. Il faut alors demander la qualite
		    {
		      int tmp(97);
		      cout << "Veuillez entrer la qualite desire. 0(Moche) - 100(Merveilleux) : " << flush;
		      cin >> ws >> tmp;
		      if (cin.fail())
			{
			  cout << "Vous n'etes meme pas capable d'entrer un chiffre.\nPar defaut la qualite sera de 97" << endl;
			  cin.clear();
			  getline(cin,poubelle);
			}
		      else
			qualite=borne(tmp,0,100); // on borne au cas ou
		    }
		  if (format!=-1) // cas ou on a un format valide
		    {
		      /*
		      Parseur p(input);
		      Coord cam_pos(100,0,0); // valeur par defaut
		      double dist_focal(100); // valeur par defaut
		      VecteurU v1(-1,0,0),v2(0,0,1); // valeur par defaut
		      Image *image=new Image(400,400); // valeur par defaut
		      Couleur kBlack;
		      Environnement *scene=new Environnement(kBlack); // valeur par defaut
		      //  Profondeur de récursion: 5 
		      Camera *cam=new Camera(cam_pos,v1,v2,dist_focal,image,scene,1,0);
		      */
		      bool OK;
		      
		      Parser p( input );
		      
		      StatusCode sc( p . chargerFichier() );
		      if ( ! sc )
			{
			  error() << "Problème de lecture du fichier" << endreq;
			  return 1;
			}
		      sc = p.lireDocument();
		      if ( ! sc )
			{
			  error() << "Problème de lecture" << endreq;
			  return 1;
			}
		      Environnement *scene;
		      Camera *cam;
		      vector< const ElementDOM* > information;
		      sc = p . getStructureFichier( information );
		      cam = lireCamera( information, OK );
		      if ( ! OK )
			{
			  error() << "Ne peut pas charger la caméra" << endreq;
			  return 1;
			}
// 		      else
// 			cout << "Caméra OK" << endl;
		      scene = lireEnvironnement( information, OK );
		      if ( ! OK )
			{
			  error() << "Ne peut pas charger l'environnement"
				  << endreq;
			  return 1;
			}
// 		      else
// 			cout << "Environnement OK" << endl;
		      cam -> env( scene );
		      try
			{
			  //p.extract(image,cam, kBlack); // les valeurs par defaut vont etre modifier
			  cam->genereImage(); // on lance les rayon
			  // on cherche le format choisi et on ecrit le fichier
			  if (format==0)
			    {
			      ImageFileJpeg mon_image(cam->film(),output,qualite);
			      mon_image.affiche();
			    }
			  if (format==1)
			    {
			      ImageFilePng mon_image(cam->film(),output);
			      mon_image.affiche();
			    }
			  if (format==2)
			    {
			      ImageFileTiff mon_image(cam->film(),output);
			      mon_image.affiche();
			    }
			  if (format==3)
			    {
			      ImageFilePPM mon_image(cam->film(),output);
			      mon_image.affiche();
			    }
			}
		      catch(Erreur &err) // en cas d'erreur dans le fichier xml
			{
			  cout << "Consulter Syntax_Error_XML.txt pour plus d info" << endl;
			  err.ecrire("Syntax_Error_XML.txt");
			}
		      // on rend la memoire au systeme
		      cout << (char)7;
		      //delete image;
		      delete cam;
		      delete scene;
		      string temp;
		      
		      
		      cout << endl << "Entrer o ou y pour continuer, n pour quitter" << endl;
		      do{               
			cin >> ws >> temp;
			cout << endl;
			if (cin.fail())
			  {
			    cin.clear();
			    getline(cin,poubelle);
			  }
		      }
		      while (temp[0]!='o' && temp[0]!='n' && temp[0]!='y');
		      ouinon=temp[0];
		    }
		  else
		    {
		      cout << "Format de fichier inconnu" << endl;
		    }
		}
	      else
		{
		  cout << "Nom de fichier invalide" << endl;
		  cin.clear();
		  getline(cin, poubelle);
		}
	    }
	  else
	    {
	      cout << "Extension XML non valide. Verifier votre nom de fichier" << endl;
	      cin.clear();
	      getline(cin, poubelle);
	    }
	}
      
    } while (ouinon=='o' || ouinon=='y');
  return 0;
}
